package com.sca4cloud.sca.microservice.start;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.xml.parsers.DocumentBuilderFactory;

import org.dom4j.Node;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.stereotype.Component;
import org.w3c.dom.NodeList;

import com.ylink.ide.dict.DictManager;

import lombok.extern.slf4j.Slf4j;

@Component
@Order(Integer.MAX_VALUE - 1)
@Slf4j
public class IDEStartSupport implements CommandLineRunner {

	@Override
	public void run(String... args) throws Exception {
		loadDict();
	}

	private void loadDict() throws IOException {
		// clrar cache
		log.debug("===================数据字典 开始加载===清除缓存==============");
		DictManager.clear();
		// 分离lib打包或者本地运行 加载方式
		String libpath = System.getProperty("user.dir") + File.separator + "lib";
		log.debug("加载字典jar 路径=" + libpath);
		File file = new File(libpath);
		if (!file.exists()) {
			log.info("classpath加载数据字典文件：classpath*:/**/*.dd ");
			// spring fatjar打包后 加载方式
			Resource[] resources = ResourcePatternUtils.getResourcePatternResolver(null)
					.getResources("classpath*:/**/*.dd");
			for (Resource r : resources) {
				log.debug("resource 文件======{}", r.getFilename());
				jdkLoad(r.getInputStream());
			}
		} else {
			File[] fs = file.listFiles();
			String jarpath = null;
			File dictJar = null;
			for (File f : fs) {
				log.debug("dictjarname>>>>>>{}", f.getName());
				String jarName = f.getName();
				if (jarName.startsWith("data.datadict") && jarName.endsWith(".jar")) {
					jarpath = f.getAbsolutePath();
					log.debug("dictjarpath>>>>>>{}", jarpath);
					dictJar = f;
					break;
				}
			}
			if (dictJar != null && dictJar.exists()) {
				@SuppressWarnings("resource")
				JarFile jarFile = new JarFile(jarpath);

				for (Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements();) {
					JarEntry entry = e.nextElement();
					String dict = entry.getName();
					if (!dict.endsWith(".dd"))
						continue;
					log.debug("字典文件名称=" + dict);
					InputStream in = jarFile.getInputStream(entry);
					jdkLoad(in);
					// dom4jLoad(in);
				}
				jarFile.close();
			}
		}
		log.info("===================数据字典 加载 完成=======================");
		log.debug("platform dict>>>>>>{}", DictManager.getPlatDict());
		log.debug("bank dict>>>>>>{}", DictManager.getBankDict());
		log.debug("app dict>>>>>>{}", DictManager.getAppDict());
	}

	private void jdkLoad(InputStream in) {
		log.debug(" jdk字典处理开始======");
		try {

			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			// 这是优先选择. 如果不允许DTDs (doctypes) ,几乎可以阻止所有的XML实体攻击
			String FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
			dbf.setFeature(FEATURE, true);

			FEATURE = "http://xml.org/sax/features/external-general-entities";
			dbf.setFeature(FEATURE, false);

			FEATURE = "http://xml.org/sax/features/external-parameter-entities";
			dbf.setFeature(FEATURE, false);

			FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
			dbf.setFeature(FEATURE, false);

			dbf.setXIncludeAware(false);
			dbf.setExpandEntityReferences(false);
			org.w3c.dom.Document document = dbf.newDocumentBuilder().parse(in);
			NodeList root = document.getElementsByTagName("DataDictionary");
			org.w3c.dom.Element rootEle = (org.w3c.dom.Element) root.item(0);
			org.w3c.dom.NodeList list = rootEle.getChildNodes();
			String key = rootEle.getAttribute("type");
			log.debug("key={}", key);
			for (int i = 0; i < list.getLength(); i++) {
				org.w3c.dom.Node node = list.item(i);
				if (node.getNodeType() == Node.ELEMENT_NODE) {
					org.w3c.dom.Element ele = (org.w3c.dom.Element) node;
					String level = ele.getAttribute("DICTTYPE");
					log.debug("level={}", level);

					if (level.equals("0")) {
						DictManager.addPlat(key, readDictXmlByjdk(rootEle));
					}
					if (level.equals("1")) {
						DictManager.addBank(key, readDictXmlByjdk(rootEle));
					}
					if (level.equals("2")) {
						DictManager.addApp(key, readDictXmlByjdk(rootEle));
					}

				}
			}

			log.debug(" ========jdk字典处理 完成======");
		} catch (Exception e) {
			e.printStackTrace();
			log.error("jdk解析异常>>>>>>>>>{}", e);
		}finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
				log.error("输入流关闭异常>>>>>>>>>{}", e);
			}
		}
	}

	private Map<String, String> readDictXmlByjdk(org.w3c.dom.Node root) {
		Map<String, String> value = new HashMap<String, String>();
		org.w3c.dom.NodeList ds = root.getChildNodes();
		for (int i = 0; i < ds.getLength(); i++) {
			org.w3c.dom.Node node = ds.item(i);
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				org.w3c.dom.Element e = (org.w3c.dom.Element) node;
				String k = e.getAttribute("name");
				String v = e.getAttribute("PUBCODECNAME");
				value.put(k, v);
			}
		}
		return value;
	}

	// private void dom4jLoad(InputStream in) {
	// log.debug(" dom4j字典处理开始======");
	// try {
	// SAXReader reader = new SAXReader(new DocumentFactory());
	// Document document = reader.read(in);
	// Element root = document.getRootElement();
	// Element e = root.element("DataField");
	// String level = e.attributeValue("DICTTYPE");
	// String key = root.attributeValue("type");
	// if (level.equals("0")) {
	// DictManager.addPlat(key, readDictXmlByDom4j(root));
	// }
	// if (level.equals("1")) {
	// DictManager.addBank(key, readDictXmlByDom4j(root));
	// }
	// if (level.equals("2")) {
	// DictManager.addApp(key, readDictXmlByDom4j(root));
	// }
	// log.debug(" dom4j字典处理 完成======");
	// } catch (Exception e) {
	// e.printStackTrace();
	// log.error("dom4j解析异常>>>>>>>>>{}", e);
	// }
	//
	// }

	// private Map<String, String> readDictXmlByDom4j(Element root) {
	// List<Element> ds = root.elements("DataField");
	// Map<String, String> value = new HashMap<String, String>();
	// for (Element e : ds) {
	// String k = e.attributeValue("name");
	// String v = e.attributeValue("PUBCODECNAME");
	// value.put(k, v);
	// }
	// return value;
	// }

}
